﻿using System;
using System.Text;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;

namespace Billing2
{
    public class AntiCSRF : System.Web.IHttpModule
    {
        public void Init(HttpApplication context)
        {
            //context.BeginRequest += new EventHandler(Application_BeginRequest);
            context.PostRequestHandlerExecute += new EventHandler(this.OnPreSendRequestContent);
        }

        protected void OnPreSendRequestContent(Object sender, EventArgs e)
        {
            System.Web.HttpApplication myContext = (System.Web.HttpApplication)sender;
            myContext.Response.Filter = new AppendSIDFilter(myContext.Response.Filter);
        }

        //private void Application_BeginRequest(object sender, EventArgs e)
        //{
        //    string token = (new Random()).Next().ToString();
        //    string url = "";
        //    HttpContext context = ((HttpApplication)sender).Context;
        //    if (string.IsNullOrEmpty(context.Request.QueryString["token"]))
        //    {
        //        if (context.Request.QueryString.Count == 0)
        //        {
        //            if (context.Request.RawUrl.EndsWith("?"))
        //                url = string.Format("{0}token={1}", context.Request.RawUrl, token);
        //            else
        //                url = string.Format("{0}?token={1}", context.Request.RawUrl, token);
        //        }
        //        else
        //        {
        //            url = string.Format("{0}&token={1}", context.Request.RawUrl, token);
        //        }
        //    }
        //    else
        //    {
        //        url = context.Request.RawUrl;
        //    }
        //    context.RewritePath(url);
        //}

        public void Dispose() { }

        public class AppendSIDFilter : Stream, System.Web.SessionState.IRequiresSessionState
        {
            private Stream Sink { get; set; }
            private long _position;
            private System.Text.StringBuilder oOutput = new StringBuilder();

            static public string GetSessionID()
            {
                if (System.Web.HttpContext.Current.Session != null)
                    return System.Web.HttpContext.Current.Session.SessionID;
                else
                    return "";
            }

            static public int GetSessionCount()
            {
                return System.Web.HttpContext.Current.Session.Count;   
            }
            
            public AppendSIDFilter(Stream sink)
            {
                Sink = sink;
            }

            public override bool CanRead
            {
                get { return true; }
            }

            public override bool CanSeek
            {
                get { return true; }
            }

            public override bool CanWrite
            {
                get { return true; }
            }

            public override long Length
            {
                get { return 0; }
            }

            public override long Position
            {
                get { return _position; }
                set { _position = value; }
            }

            public override long Seek(long offset, System.IO.SeekOrigin direction)
            {
                return Sink.Seek(offset, direction);
            }

            public override void SetLength(long length)
            {
                Sink.SetLength(length);
            }

            public override void Close()
            {
                Sink.Close();
            }

            public override void Flush()
            {
                Sink.Flush();
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                return Sink.Read(buffer, offset, count);
            }

            const string RegexHref = @" href=[""']([a-zA-Z0-9_-]+)\.aspx""";
            const string RegexAction = "";

            public override void Write(byte[] buffer, int offset, int count)
            {
                string content = System.Text.UTF8Encoding.UTF8.GetString(buffer, offset, count);

                //string token = HttpContext.Current.Request.QueryString["token"];
                string token = HttpContext.Current.Request.Cookies["token"].Value;

                if (string.IsNullOrEmpty(token))
                {
                    Sink.Write(buffer, 0, buffer.Length);
                    return;
                }

                Regex regex = new Regex(RegexHref, RegexOptions.IgnoreCase);
                if (regex.IsMatch(content))
                {
                    content = Regex.Replace(content, RegexHref, new MatchEvaluator(ReplaceSID), RegexOptions.Compiled | RegexOptions.IgnoreCase);
                }
                //Regex action_regex = new Regex(RegexAction, RegexOptions.IgnoreCase);
                //if (action_regex.IsMatch(content))
                //{
                //    content = Regex.Replace(content, RegexAction, new MatchEvaluator(ReplaceSID), RegexOptions.Compiled | RegexOptions.IgnoreCase);
                //}

                byte[] data = System.Text.UTF8Encoding.UTF8.GetBytes(content);
                Sink.Write(data, 0, data.Length);
            }

            public static string ReplaceSID(Match match)
            {
                if (match.Value.IndexOf("token=") != -1)
                {
                    return match.Value;
                }
                string result;
                if (match.Value.IndexOf('?') == -1)
                {
                    result = match.Value.Insert(match.Value.Length - 1, "?token=" + Common.CreateToken());
                }
                else
                {
                    result = match.Value.Insert(match.Value.Length - 1, "&token=" + Common.CreateToken());
                }
                return result;
            }
        }
    }
}
